
/**
 * @class ObjectTreePanel
 * @extends Ext.tree.TreePanel
 */
var ObjectTreePanel = function(el, config) {
  config.draggable = typeof (config.draggable) == 'undefined' ? true : config.draggable;

  ObjectTreePanel.superclass.constructor.call(this, el, {
    ddGroup : 'BindingObjectDD',
    animate : true,
    enableDrag : config.draggable,
    containerScroll : true
  }); 
  this.name = config.name;
  this.setObject(config.obj || {});
  
}

Ext.extend(ObjectTreePanel, Ext.tree.TreePanel, {
  beforeLoad : function() {
    this.getRootNode().getUI().beforeLoad();
  }
  ,
  setObject : function(obj) {
    this.el.update('');
    this.targetObj = obj;
    var root = new ObjectTreeNode(this.name, this.name, this.targetObj);
    this.setRootNode(root);
    this.render();
    root.expand();
  }
});


/**
 * @class ObjectTreeNode
 * @extends Ext.tree.TreeNode
 */
var ObjectTreeNode = function(path, name, obj, cfg) {
  cfg = jQuery.extend({text : name,
                            uiProvider : ObjectTreeNodeUI}, cfg || {})

  ObjectTreeNode.superclass.constructor.call(this,cfg);
  this.name = name;
  this.path = path;
  this.setValue(obj);
}

Ext.extend(ObjectTreeNode, Ext.tree.TreeNode, {

  setValue : function(value) {
    mb.lang.forEach(this.childNodes.slice(), function(c) { this.removeChild(c) }, this);
    this.value = value;
    if (mb.lang.isDOMNode(value)) {
      var div = mb.dom.createElement({ className : 'af-render-root' });
      div.appendChild(value);
      this.setText(this.name + mb.dom.toHTML(div));
    } 
	else if (value instanceof mb.Renderer) {
      this.setText(this.name);
    } 
	else if (jQuery.isArray(value)) {
      mb.lang.forEach(value, function(val, i) {
        var n = null;
        if(val.myCocktailName)
          n = val.myCocktailName;
        else if(val.name)
          n = val.name;
        else if(val.title)
          n = val.title;
        else
          n = '['+i+']';
        var p = this.path + '['+i+']';
        var cfg = {}
        if(val.myCocktailIcon)
          cfg.icon = val.myCocktailIcon;
        this.appendChild(new ObjectTreeNode(p, n, val, cfg));
      }, this);

    } 
	else if (mb.lang.isObject(value)) {
      mb.lang.forEach(mb.lang.keys(value), function(key) {
        if (key != 'myCocktailIcon' && key != 'myCocktailName'){
          if (mb.lang.isSerializable(value[key])) {
            var p = this.path + (/^\w[\w\d]*$/.test(key) ? '.'+key : '["'+key+'"]');
            this.appendChild(new ObjectTreeNode(p, key, value[key]));
          }
        }
      }, this);
    } 
	else if (value !== null && typeof value != 'undefined') {
      var str = mb.string.escapeHTML(value.toString());
      str = str.length>100 ? str.substring(0, 100) + '...' : str;
      this.setText(this.name + ' : ' + str);
    } 
	else {
      this.setText(this.name);
    }
  }
});

/**
 * @class ObjectTreeNodeUI
 * @extends Ext.tree.TreeNodeUI
 */
var ObjectTreeNodeUI = function() {
  ObjectTreeNodeUI.superclass.constructor.apply(this, arguments);
}

Ext.extend(ObjectTreeNodeUI, Ext.tree.TreeNodeUI, {
  render : function() {
    ObjectTreeNodeUI.superclass.render.apply(this, arguments);
    if (this.node.value instanceof mb.Renderer) {
      var renderer = this.node.value;
      var el = mb.dom.createElement({ className : 'af-rendered' });
      this.textNode.appendChild(el);
      renderer.render(el);
    }
  }
});


/**
 * @class OutputTreeView
 */
var OutputTreeView = mb.lang.defineClass({
  initialize : function(el, name, draggable) {
    this.el = el;
    this.outputTree = new ObjectTreePanel(this.el.createChild(), {
      name : name,
      draggable : draggable
    });
  }
  ,  
  prepare : function() {
    this.outputTree.beforeLoad();
  }
  ,
  render : function(value) {
    this.outputTree.setObject(value);
  }
  ,
  reset : function() {
    this.outputTree.setObject(null);
  }
});


/**
 * @class OutputGridView
 */
var OutputGridView = mb.lang.defineClass({
  initialize : function(el, name, draggable) {
    this.el = el;
    this.ds = new Ext.data.Store({
      proxy : new Ext.data.MemoryProxy({ records : [] }),
      reader : new Ext.data.JsonReader({ root : 'records' }, [ 'header' ])
    });
    this.cm = new Ext.grid.ColumnModel([
      { header : 'header', dataIndex : 'header', width : this.el.up('div').getWidth()-18 }
    ]);

    this.grid = new Ext.grid.Grid(this.el, {
      ds : this.ds, 
      cm : this.cm,
      autoHeight : true,
      maxHeight : 250
    });
    this.ds.load();
    this.grid.render();
  }
  ,
  prepare : function() {
    if (this.ds) this.ds.removeAll();
  }
  ,
  render : function(value) {
    if (typeof value == 'undefined' || value===null) return;

    var records = jQuery.isArray(value) ? value : [ value ];

    var fields = {};
    records = jQuery.map(records, function(record) {
      if (mb.lang.isObject(record) && 
          !(record instanceof mb.Renderer) &&
          !mb.lang.isDOMNode(record)) {
        jQuery.each(mb.lang.keys(record), function(i, field) {
          fields[field] = true; 
        });
        return record;
      } 
	  else {
        fields['element'] = true;
        return { element : record }
      }
    });
    fields = mb.lang.keys(fields);

    this.ds = new Ext.data.Store({
      proxy : new Ext.data.MemoryProxy({ records : records }),
      reader : new Ext.data.JsonReader({ root : 'records' }, fields)
    });
    var colwidth = Math.floor((this.el.up('div').getWidth()-18) / fields.length);
    this.cm = new Ext.grid.ColumnModel(
      jQuery.map(fields, function(f) {
        return {
          header : f,
          dataIndex : f, 
          renderer : renderCell,
          width : colwidth 
        }
      })
    );
    this.grid.reconfigure(this.ds, this.cm);
    this.ds.load();
    this.grid.render();

    function renderCell(value, p, record) {
      if (jQuery.isArray(value)) {
        return '[array]';
      }
      if (mb.lang.isDOMNode(value)) {
        return mb.dom.toHTML(value);
      } 
      if (value instanceof mb.Renderer) {
        var el = mb.dom.createElement(); 
        value.render(el);
        return el.innerHTML;
      }
      if (mb.lang.isObject(value)) {
        return '[object]';
      }
      return mb.lang.toString(value);
    }
  }
  ,
  reset : function() {
    this.el.update('');
  }
});


/**
 * @class SelectBox
 * @extends Ext.form.ComboBox
 */
var SelectBox = function(config) {
  SelectBox.superclass.constructor.call(this, {
    fieldLabel : config.fieldLabel,
    name : config.name,
    displayField : 'label',
    editable : config.editable,
    typeAhead: true,
    triggerAction: 'all',
    selectOnFocus : true,
    forceSelection : true,
    store: new Ext.data.SimpleStore({
      fields : [ 'value', 'label' ],
      data : mb.lang.map(config.options, function(o) { return [ o, o ] })
    }),
    width : config.width
  });
}
Ext.extend(SelectBox, Ext.form.ComboBox, {});